﻿using System;
using System.IO;
using System.Net;
using System.Threading.Tasks;
using System.Web.Script.Serialization;
using System.Xml.Linq;

namespace MusicPlow
{
    public static class WebRequestExtensions
    {
        public static Task<WebResponse> GetReponseAsync(this WebRequest request)
        {
            return Task.Factory.FromAsync<WebResponse>(
                            request.BeginGetResponse,
                            request.EndGetResponse,
                            null);
        }
        
        private static Task<T> ExecuteWebRequest<T>(string requestUri, string contentType, Func<string, T> onResponseReady,
            Action<WebRequest> onBeforeSendRequest)
        {
            WebRequest request = WebRequest.Create(requestUri);
            request.Method = WebRequestMethods.Http.Get;
            request.ContentType = contentType;

            if (onBeforeSendRequest != null)
            {
                onBeforeSendRequest(request);
            }

            return request.GetReponseAsync().ContinueWith<T>(t =>
            {
                string responseStr;
                using (t.Result)
                {
                    using (var rdr = new StreamReader(t.Result.GetResponseStream()))
                    {
                        responseStr = rdr.ReadToEnd();
                    }
                }

                return onResponseReady(responseStr);
            });
        }

        public static Task<T> ExecuteJsonWebRequestTask<T>(string requestUri, Func<dynamic, T> onResponse)
        {
            return ExecuteJsonWebRequestTask(requestUri, onResponse, null);
        }
        
        public static Task<T> ExecuteJsonWebRequestTask<T>(string requestUri, Func<dynamic, T> onResponse,
            Action<WebRequest> onBeforeSendRequest)
        {
            return ExecuteWebRequest<T>(requestUri, "application/json; charset=utf-8", 
                resultAsStr => 
                    {
                        try
                        {
                            JavaScriptSerializer jss = new JavaScriptSerializer();
                            dynamic structuredResult = jss.Deserialize<dynamic>(resultAsStr);
                            return onResponse(structuredResult);
                        }
                        catch
                        {
                            return default(T);
                        }
                    }, onBeforeSendRequest);
        }

        public static Task<T> ExecuteXMLWebRequestTask<T>(string requestUri, Func<XDocument, T> onResponse)
        {
            return ExecuteXMLWebRequestTask(requestUri, onResponse, null);
        }
        
        public static Task<T> ExecuteXMLWebRequestTask<T>(string requestUri, Func<XDocument, T> onResponse,
            Action<WebRequest> onBeforeSendRequest)
        {
            return ExecuteWebRequest<T>(requestUri, "application/xml; charset=utf-8",
                resultAsStr =>
                {
                    try
                    {
                        return onResponse(XDocument.Parse(resultAsStr));
                    }
                    catch
                    {
                        return default(T);
                    }
                }, onBeforeSendRequest);
        }
    }
}
